# 导入所需要的模块opencv，numpy，math
import cv2 as cv
import copy
import matplotlib.pyplot as plt

"""
    1、以Lena为原始图像，通过OpenCV实现平均滤波，高斯滤波及中值滤波，比较滤波结果
"""
# 原始图片读取，图片通道为BGR
srcImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\lena.jpg')

# 均值滤波，(3,3)为卷积模板大小
aveBlurImg = cv.blur(srcImg, (3, 3))
# 高斯滤波
gaussianBlurImg = cv.GaussianBlur(srcImg, (3, 3), 0, 0)
# 中值滤波
medianBlurImg = cv.medianBlur(srcImg, 5)

# 显示原图和处理后的图形
cv.imshow('Source Img', srcImg)
cv.imshow('AveBlur Img', aveBlurImg)
cv.imshow('GausBlur Img', gaussianBlurImg)
cv.imshow('MediBlur Img', medianBlurImg)

cv.waitKey()
cv.destroyAllWindows()

"""
    2、以Lena为原始图像，通过OpenCV使用Sobel及Canny算子检测，比较边缘检测结果
"""
# 原始图片读取，图片通道为BGR
srcImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\lena.jpg')

# 高斯滤波
gaussianBlurImg = cv.GaussianBlur(srcImg, (3, 3), 0, 0)
# 高斯滤波后，原图转换成灰度图片
grayImg = cv.cvtColor(gaussianBlurImg, cv.COLOR_BGR2GRAY)

# Sobel算子边缘检测
sobelImg = cv.Sobel(grayImg, cv.CV_64F, 1, 1, ksize=3)

# Canny算子边缘检测(50:为x方向梯度阈值，150:为y方向梯度阈值)
cannyImg = cv.Canny(grayImg, 50, 150)

# 显示原图和处理后的图形
cv.imshow('Source Img', srcImg)
cv.imshow('Sobel Img', sobelImg)
cv.imshow('Canny Img', cannyImg)

cv.waitKey()
cv.destroyAllWindows()

"""
    3、在OpenCV安装目录下找到课程对应演示图片(安装目录\sources\samples\data)，
    首先计算灰度直方图，进一步使用大津算法进行分割，并比较分析分割结果
"""
# 图片读取
srcImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\rice.jpg')

# 图像，通道[0]-灰度图，掩膜-无，灰度级，像素范围
calcImg = cv.calcHist([srcImg], [0], None, [256], [0, 255])

# 原图
plt.subplot(221), plt.imshow(srcImg, 'gray')
# 灰度直方图
plt.subplot(222), plt.plot(calcImg)
plt.show()

# 原图转为二值图
grayImg = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY)
# 大津算法阈值化(元组拆包)
retval, dst = cv.threshold(grayImg, 0, 255, cv.THRESH_OTSU)

# 展示原图与大津算法分割后的图片
cv.imshow('srcImg', srcImg)
cv.imshow('OTSU', dst)
cv.waitKey()
cv.destroyAllWindows()

"""
    4. 使用米粒图像，分割得到各米粒，首先计算各区域(米粒)的面积、长度等信息，
    进一步计算面积、长度的均值及方差，分析落在3sigma范围内米粒的数量
"""

# 米粒图片读取
srcImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\rice.jpg')

# 图片二值化
grayImg = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY)
# 大津算法阈值化(元组拆包)
_, bw = cv.threshold(grayImg, 0, 0xff, cv.THRESH_OTSU)
# 形态学处理，去除噪音
element = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))
# 阈值化处理后的图片
bwImg = cv.morphologyEx(bw, cv.MORPH_OPEN, element)

# 对图像进行分割
seg = copy.deepcopy(bw)
# 找米粒/找目标轮廓
bin, cnts, hier = cv.findContours(seg, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# 初始化米粒数量
rice_count = 0

for i in range(len(cnts), 0, -1):
    c = cnts[i - 1]
    # 米粒面积计算
    area = cv.contourArea(c)
    if area < 10:
        continue
    rice_count = rice_count + 1
    print("blob", i, " 的面积：", area)

    x, y, w, h = cv.boundingRect(c)
    cv.rectangle(srcImg, (x, y), (x + w, y + h), (0, 0, 0xff), 1)
    cv.putText(srcImg, str(rice_count), (x, y), cv.FONT_HERSHEY_PLAIN, 0.5, (0, 0xff, 0))

print("米粒的数量：", rice_count)
cv.imshow('srcImg', srcImg)
cv.imshow('bwImg', bwImg)

cv.waitKey()
cv.destroyAllWindows()

"""
    5. 使用棋盘格及自选风景图像，分别使用SIFT、FAST及ORB算子检测角点，并比较分析检测结果
"""
# --------------  SIFT算子检测角点 -----------------
# 读取棋盘图
chessImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\chessboard.png')
# 读取风景图
viewImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\home.jpg')

# 棋盘相对尺寸缩小，颜色转换为灰色
height, width = chessImg.shape[:2]
newSize_cheImg = cv.resize(chessImg, (int(width / 8), int(height / 8)), interpolation=cv.INTER_CUBIC)
chesGrayImg = cv.cvtColor(newSize_cheImg, cv.COLOR_BGR2GRAY)

# 风景图片颜色转换为灰色
viewGrayImg = cv.cvtColor(viewImg, cv.COLOR_BGR2GRAY)

cv.imshow('chesGrayImg', chesGrayImg)
cv.imshow('viewGrayImg', viewGrayImg)

# 创建SIFT对象
sift = cv.xfeatures2d.SIFT_create()

# 对棋盘图进行检测
ches_keypoints, ches_descriptor = sift.detectAndCompute(chesGrayImg, None)

ches_sifiImg = cv.drawKeypoints(image=chesGrayImg, outImage=chesGrayImg,
                                keypoints=ches_keypoints, flags=cv.DRAW_MATCHES_FLAGS_DEFAULT,
                                color=(0, 0, 255))

# 对风景图进行检测
view_keypoints, descriptor = sift.detectAndCompute(viewGrayImg, None)

view_sifiImg = cv.drawKeypoints(image=viewGrayImg, outImage=viewGrayImg,
                                keypoints=view_keypoints, flags=cv.DRAW_MATCHES_FLAGS_DEFAULT,
                                color=(0, 0, 255))

cv.imshow('ChesImg_SIFI', ches_sifiImg)
cv.imshow('ViewImg_SIFI', view_sifiImg)
cv.waitKey()
cv.destroyAllWindows()

# --------------  FAST算子检测角点 -----------------
# 读取棋盘图
chessImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\chessboard.png')
# 读取风景图
viewImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\home.jpg')

# 棋盘相对尺寸缩小，颜色转换为灰色
height, width = chessImg.shape[:2]
newSize_cheImg = cv.resize(chessImg, (int(width / 8), int(height / 8)), interpolation=cv.INTER_CUBIC)
chesGrayImg = cv.cvtColor(newSize_cheImg, cv.COLOR_BGR2GRAY)

# 风景图片颜色转换为灰色
viewGrayImg = cv.cvtColor(viewImg, cv.COLOR_BGR2GRAY)

cv.imshow('chesGrayImg', chesGrayImg)
cv.imshow('viewGrayImg', viewGrayImg)

# FAST算子检测角点
# FAST对象定义
fast_chess = cv.FastFeatureDetector_create(threshold=10, nonmaxSuppression=True,
                                           type=cv.FAST_FEATURE_DETECTOR_TYPE_7_12)

fast_view = cv.FastFeatureDetector_create(threshold=40, nonmaxSuppression=True,
                                          type=cv.FAST_FEATURE_DETECTOR_TYPE_9_16)

# 对指定图片角点检测
fast_keypoints_ches = fast_chess.detect(chesGrayImg, None)
fast_keypoints_view = fast_view.detect(viewGrayImg, None)

# 标注角点
chesGrayImg_fast = cv.drawKeypoints(chesGrayImg, fast_keypoints_ches, None, color=(0, 0, 255))
viewGrayImg_fast = cv.drawKeypoints(viewGrayImg, fast_keypoints_view, viewGrayImg, color=(0, 0, 255))

# 展示检测结果
cv.imshow('ChesImg_FAST', chesGrayImg_fast)
cv.imshow('ViewImg_FAST', viewGrayImg_fast)
cv.waitKey()
cv.destroyAllWindows()

# --------------  ORB算子检测角点 -----------------
# 读取棋盘图
chessImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\chessboard.png')
# 读取风景图
viewImg = cv.imread(r'C:\Users\HuangSX\Pictures\Saved Pictures\home.jpg')

# 棋盘相对尺寸缩小，颜色转换为灰色
height, width = chessImg.shape[:2]
newSize_cheImg = cv.resize(chessImg, (int(width / 8), int(height / 8)), interpolation=cv.INTER_CUBIC)
chesGrayImg = cv.cvtColor(newSize_cheImg, cv.COLOR_BGR2GRAY)

# 风景图片颜色转换为灰色
viewGrayImg = cv.cvtColor(viewImg, cv.COLOR_BGR2GRAY)

cv.imshow('chesGrayImg', chesGrayImg)
cv.imshow('viewGrayImg', viewGrayImg)

# ORB算子检测角点
# ORB对象定义
orb = cv.ORB_create()

# 角点检测
ches_kps = orb.detect(chesGrayImg, None)
view_kps = orb.detect(viewGrayImg, None)

chesGrayImg_orb = cv.drawKeypoints(chesGrayImg, ches_kps, None, color=(0, 0, 255))
viewGrayImg_orb = cv.drawKeypoints(viewGrayImg, view_kps, None, color=(0, 0, 255))

# 展示检测结果
cv.imshow('ChesImg_ORB', chesGrayImg_orb)
cv.imshow('ViewImg_ORB', viewGrayImg_orb)
cv.waitKey()
cv.destroyAllWindows()
